package com;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

/**
 * @Classname: NIODemo1
 * @Author: bromide
 * @CreateTime: 2022/4/17--9:36
 * @Version: V1.0
 * @Description:
 * JAVA NIO
 * NIO称为非阻塞IO。读写的过程中不会发生阻塞线程
 * 我们之前所学习的流，称为BIO：阻塞式IO，就是在读写的过程中可能会发生阻塞现象
 */
public class NIODemo1 {
    public static void main(String[] args) throws IOException {
        /*
            非阻塞IO面向Channel("通道")的，不是面向Stream(流)的。

            流的特点：方向单一，顺序读写。流要么是输入流用于顺序读取数据，要么是输出流用于顺序写出数据

            Channel的特点：双向的，既可以读又可以写。

            JAVA NIO核心API：
            Channel 通道，常见的实现：
            FileChannel：文件通道，可以对文件进行读写操作
            SocketChannel：套接字通道，可以与远端计算机进行TCP读写操作
            ServerSocketChannel:服务端的套接字通道，用于监听客户端的连接

            Buffer缓冲区，通道是对缓冲区中的数据进行读写操作
            常见的缓冲区实现
            ByteBuffer:字节缓冲区，缓冲区内部内容都是字节
         */
        //NIO的文件复制操作
        FileInputStream fis = new FileInputStream("movie.wmv");
        //基于文件输入流获得一个通道
        FileChannel inChannel = fis.getChannel();

        FileOutputStream fos = new FileOutputStream("movie_cp.wmv");
        FileChannel outChannel = fos.getChannel();

        //创建一个字节缓冲区
        ByteBuffer buffer = ByteBuffer.allocate(1024*10);//创建一个10K大小的缓冲区
        int len;//记录每次实际读取的数据量
        /*
            缓冲区中重要的几个属性：
            position:当前位置，用来表示当前缓冲区已经有多少数据被操作了
            limit:缓冲区最大可以操作的位置
            capacity:容量，缓冲区的大小

            默认创建要给缓冲区时:
            position=0;
            limit=capacity;
            capacity=创建缓冲区时指定的大小
         */
        /*
            position=0
            limit=10240
            一次可以最多读取数据为：position到limit之间的数据量
            limit-position = 10240
         */
//        System.out.println("读取前======================");
//        System.out.println("position:"+buffer.position());
//        System.out.println("limit:"+buffer.limit());
//        len = inChannel.read(buffer);//从通道中读取数据到缓冲区中
//        System.out.println("读取到了"+len+"个字节");
//        System.out.println("读取后======================");
//        System.out.println("position:"+buffer.position());
//        System.out.println("limit:"+buffer.limit());
//        System.out.println("第二次读取================================");
//        System.out.println("读取前======================");
//        System.out.println("position:"+buffer.position());
//        System.out.println("limit:"+buffer.limit());
//        len = inChannel.read(buffer);//从通道中读取数据到缓冲区中
//        System.out.println("读取到了"+len+"个字节");
//        System.out.println("读取后======================");
//        System.out.println("position:"+buffer.position());
//        System.out.println("limit:"+buffer.limit());
        //完成一轮复制
        /*
            读取前
            position:0
            limit:10240
         */
//        len = inChannel.read(buffer);//一次读取了10K数据
        /*
            读取后
            position:10240
            limit:10240
         */
        /*
            write在写出一个缓冲区时，写出的也是缓冲区中的position与limit之间的数据

            总结：
            Channel通道在进行读或写操作时，具体可以读取多少个字节或写出多少个字节是
            取决于我们传入的Buffer中position到limit之间的空间
         */
//        buffer.flip();
        /*
            flip后：
            position:0
            limit:10240
         */
//        outChannel.write(buffer);//向文件movie_cp.wmv中写入10k

        //完整的复制动作
        while ((len = inChannel.read(buffer))!=-1){
            buffer.flip();
            outChannel.write(buffer);
            buffer.clear();
        }



    }
}
